package org.openfantasia.musica.instruments.jmusic;

import jm.audio.Instrument;
import jm.audio.io.SampleOut;
import jm.audio.synth.*;

/**
 * A basic additive synthesis instrument implementation
 * which implements an envelope and allows specification
 * of the overtone frequency ratios and volume levels.
 *
 * @author Andrew Brown and Andrew Sorensen
 */
public final class AddSynthInst extends Instrument {
	//----------------------------------------------
	// Attributes
	//----------------------------------------------

	/**
	 * the relative overtoneRatios which make up this note
	 */
	private double[] overtoneRatios;

	/**
	 * the overtoneVolumes to use for each frequency
	 */
	private double[] overtoneVolumes;

	/**
	 * The points to use in the construction of Envelopes
	 */
	private double[][] allEnvPoints;

	/**
	 * Default Envelope Values
	 */
	private double[] envPoints = {0.0, 0.0, 0.05, 1.0, 0.15, 0.4, 0.9, 0.3, 1.0, 0.0};

	/**
	 * The sample rate to use
	 */
	private int sampleRate;

	//----------------------------------------------
	// Constructors
	//----------------------------------------------


	/**
	 * Basic default constructor to set an initial sampling rat.
	 *
	 * @param sampleRate
	 */
	public AddSynthInst(int sampleRate) {
		//Provide some defaults
		this.sampleRate = sampleRate;

		double[][] tempPoints = new double[5][];
		for (int i = 0; i < 5; i++) {
			tempPoints[i] = envPoints;
		}
		allEnvPoints = tempPoints;

		double[] temp1 = {1.0f, 3.0f, 5.0f, 7.0f, 9.0f};
		this.overtoneRatios = temp1;
		double[] temp2 = {1.0f, 0.5f, 0.35f, 0.25f, 0.15f};
		this.overtoneVolumes = temp2;
	}


	/**
	 * Basic default constructor to set an initial
	 * sampling rate and buffersize in addition
	 * to the neccessary frequency relationships
	 * and overtoneVolumes for each frequency to be added
	 * the instrument
	 *
	 * @param sampleRate
	 * @param overtoneRatios	the relative freqencies to use
	 * @param overtoneVolumes the overtoneVolumes to use for the overtoneRatios
	 * @param envPointArray	 A two dimensional array of doubles as break point values between 0.0 and 1.0
	 */
	public AddSynthInst(int sampleRate, double[] overtoneRatios,
			double[] overtoneVolumes, double[][] envPointArray) {
		this.overtoneRatios = overtoneRatios;
		this.overtoneVolumes = overtoneVolumes;
		// add envelopes for each harmonic
		//double[][] tempPoints = new double[envPointArray.length][];
		//for (int i=0; i<envPointArray.length; i++) {
		//	tempPoints[i] = envPoints;
		//}
		allEnvPoints = envPointArray; //tempPoints;

		this.sampleRate = sampleRate;
	}

	//----------------------------------------------
	// Methods 
	//----------------------------------------------


	/**
	 * Initialisation method is used to build the objects that
	 * this instrument will use
	 */
	public void createChain() {
		Envelope[] env = new Envelope[overtoneRatios.length];
		Volume[] vol = new Volume[overtoneRatios.length];
		Oscillator[] osc = new Oscillator[overtoneRatios.length];
		for (int i = 0; i < overtoneRatios.length; i++) {
			osc[i] = new Oscillator(this, Oscillator.SINE_WAVE,
					this.sampleRate, 2);
			osc[i].setFrqRatio((float) overtoneRatios[i]);
			env[i] = new Envelope(osc[i], allEnvPoints[i]);
			vol[i] = new Volume(env[i], (float) overtoneVolumes[i]);
		}
		//And now the add object brings us back to one path.
		Add add = new Add(vol);
		StereoPan span = new StereoPan(add);
		SampleOut sout = new SampleOut(span);
	}
}
